﻿/*
 * logshow.cpp
 *
 *  Created on: 2016年11月5日
 *      Author: work
 */

#include <boost/program_options.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/os/log/logmonitor.hpp>
#include <string>
#include <iostream>
#include <dm/string/stringref.hpp>
#include <dm/datetime.hpp>
#include <dm/os/signal_handler.hpp>

using namespace std;
using namespace boost::program_options;
using namespace dm::os;

class CMyLogMonitor:public dm::os::CLogMonitor{
public:
	CMyLogMonitor():CLogMonitor(),m_filter_pid(0),m_filter_module(),m_filter_obj(0),
		m_filter_level(CLogInfo::Info),m_show_pos(false),m_show_obj(false),m_show_pid(false),m_show_time(true){
	}

	inline void setFilter_pid( const dm::os::CLogInfo::pid_t& pid ){
		m_filter_pid = pid;
	}

	inline void setFiter_module( const char* module ){
		m_filter_module = module;
	}

	inline void setFilter_obj( const CLogInfo::obj_t& obj ){
		m_filter_obj = obj;
	}

	inline void setFilter_level( const CLogInfo::ELevel& level ){
		m_filter_level = level;
	}

	inline void setShow_pos( const bool& s ){
		m_show_pos = s;
	}

	inline void setShow_time( const bool& s ){
		m_show_time = s;
	}

	inline void setShow_pid( const bool& s ){
		m_show_pid = s;
	}

	inline void setShow_obj( const bool& s ){
		m_show_obj = s;
	}

	void onNew( const ringpos_t& pos,const CLogInfo& info,const bool& overflow )const{
		if( m_show_pos )
			cout <<pos.getCycle() <<'.'<<pos.getPos();

		if( m_show_time ){
			cout<<"["<<dm::CDateTime(info.t).toString()<<"]";
		}

		if( overflow )
			cout <<"(of)";

		if(m_show_pid )
			cout <<"pid:"<<info.pid<<" ";

		if(m_show_obj ){
			printf(" obj:%llX ",(unsigned long long)info.obj);
		}

		switch( info.level ){
		case CLogInfo::Debug:
			cout <<"Debug  ";
			break;
		case CLogInfo::Info:
			cout <<"Info   ";
			break;
		case CLogInfo::Warnning:
			cout <<"Warn   ";
			break;
		case CLogInfo::Error:
			cout <<"Error  ";
			break;
		default:
			cout <<"Unknow ";
		}

		cout <<info.module.c_str()
			<<"::"<<info.fun.c_str()
				<<"{"<<info.msg.c_str()
				<<"}";

		cout<<endl;

	}

	bool filter( const ringpos_t& /*pos*/,const CLogInfo& info,const bool& /*overflow*/ )const{
		if( m_filter_pid!=0 && info.pid!=m_filter_pid )
			return true;

		if( info.level<m_filter_level )
			return true;

		if( !m_filter_module.empty() && info.module!=m_filter_module.c_str() )
			return true;

		if( m_filter_obj!=0 && info.obj!=m_filter_obj )
			return true;

		return false;
	}

private:
	CLogInfo::pid_t m_filter_pid;
	string m_filter_module;
	CLogInfo::obj_t m_filter_obj;
	CLogInfo::ELevel m_filter_level;

	bool m_show_pos;
	bool m_show_obj;
	bool m_show_pid;
	bool m_show_time;
};

static const char* logModule = "logshow.app.dm";

int main( int argc,char* argv[] ){
	options_description desc("日志查看工具 @DM2016");
	desc.add_options()
			("help,h","显示本帮助信息")
			("version,v","显示版本及编译信息")
			("test,t",value<string>(),"测试日志发送功能")
			("auto,a","自动产生日志")
			("interval,i",value<int>(),"自动产生间隔")
			("pid,p",value<CLogInfo::pid_t>(),"指定进程号")
			("module,m",value<string>(),"指定模块名")
			("obj",value<string>(),"指定对象标识。16进制数")
			("level,l",value<string>(),"指定级别.debug,info*,warn,error.")
			("reset","复位日志系统")
			("show-pos","显示位置序号")
			("show-no-pos","不显示位置序号*")
			("show-time","显示时标*")
			("show-no-time","不显示时标")
			("show-pid","显示进程号*")
			("show-no-pid","不显示进程号")
			("show-obj","显示对象标识")
			("show-no-obj","不显示对象标识*")
			;

	variables_map vm;
	try{
		store(parse_command_line(argc,argv,desc),vm);
		notify(vm);
	}catch( std::exception& ex ){
		cout << ex.what()<<endl;
		return 1;
	}

	if( vm.count("version") ){
		cout <<"V1.0 构建于 "<<__DATE__<<endl;
		return 1;
	}

	if( vm.count("help") ){
		cout <<desc<<endl;
		return 1;
	}

	dm::os::CSignalHandler& sig = dm::os::CSignalHandler::ins();

	if( vm.count("reset") ){
		cout <<"复位日志系统..."<<endl;
		dm::os::CLogMgr::remove();
		return 0;
	}

	if( vm.count("test") ){
		cout <<"测试发送日志: "<<endl;
		CLogger& loger = CLogger::ins();
		unsigned int sn = 1;
		unsigned long i = 10000;
		if( vm.count("interval") && vm["interval"].as<int>() >0 )
			i = vm["interval"].as<int>();

		do{
			loger.info(STATICMODULE "%d,%s",sn,vm["test"].as<string>().c_str());
			++sn;

			if (sig.ifSignal())
				break;

#ifndef WIN32
			usleep(i);
#else
			Sleep(i);
#endif
		}while( vm.count("auto") || cin.get()!='q' );

		return 0;
	}

	CMyLogMonitor logMonitor;

	if( vm.count("pid") )
		logMonitor.setFilter_pid( vm["pid"].as<CLogInfo::pid_t>());

	if( vm.count("module") )
		logMonitor.setFiter_module( vm["module"].as<string>().c_str() );

	if( vm.count("obj") ){
		string obj = vm["obj"].as<string>();
		dm::string::CStringRef sr(obj.c_str() );
		CLogInfo::obj_t obj_value;
		if( !sr.getHexes((dm::uint8*)&obj_value,sizeof(obj_value)) ){
			cout <<"请输入正确的对象标识"<<endl;
			return 0;
		}

		logMonitor.setFilter_obj(obj_value);
	}

	if( vm.count("level") ){
		if( vm["level"].as<string>()=="debug" )
			logMonitor.setFilter_level( CLogInfo::Debug );
		else if( vm["level"].as<string>()=="info" )
			logMonitor.setFilter_level( CLogInfo::Info );
		else if( vm["level"].as<string>()=="warn" )
			logMonitor.setFilter_level( CLogInfo::Warnning );
		else if( vm["level"].as<string>()=="error" )
			logMonitor.setFilter_level( CLogInfo::Error );
		else{
			cout <<"请输入正确的级别."<<endl;
			return 0;
		}
	}

	if( vm.count("show-pos") )
		logMonitor.setShow_pos(true);
	else if( vm.count("show-no-pos"))
		logMonitor.setShow_pos(false);

	if( vm.count("show-time") )
		logMonitor.setShow_time(true);
	else if( vm.count("show-no-time"))
		logMonitor.setShow_time(false);

	if( vm.count("show-pid") )
		logMonitor.setShow_pid(true);
	else if( vm.count("show-no-pid"))
		logMonitor.setShow_pid(false);

	if( vm.count("show-obj") )
		logMonitor.setShow_obj(true);
	else if( vm.count("show-no-obj"))
		logMonitor.setShow_obj(false);

	logMonitor.run();

	return 0;
}


